From 5492f09ec07514cf8543bc06c34556e24b590852 Mon Sep 17 00:00:00 2001 From: Jonas Lochmann Date: Mon, 3 Nov 2025 01:00:00 +0100 Subject: [PATCH] odhcp6c: apply draft-ietf-6man-slaac-renum-11 lifetime rules MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Instead of applying the complicated ruleset from RFC 4862, just use the new address information as described in the draft draft-ietf-6man-slaac-renum-11. Signed-off-by: Jonas Lochmann Link: https://github.com/openwrt/odhcp6c/pull/114 Signed-off-by: Álvaro Fernández Rojas --- src/dhcpv6.c | 4 ++-- src/odhcp6c.c | 54 +++++---------------------------------------------- src/odhcp6c.h | 2 +- src/ra.c | 22 +++++++++++++++------ 4 files changed, 24 insertions(+), 58 deletions(-) diff --git a/src/dhcpv6.c b/src/dhcpv6.c index 7f73699..872f169 100644 --- a/src/dhcpv6.c +++ b/src/dhcpv6.c @@ -1742,7 +1742,7 @@ static unsigned int dhcpv6_parse_ia(void *opt, void *end, int *ret) } if (update_state) { - if (odhcp6c_update_entry(STATE_IA_PD, &entry, 0, 0)) + if (odhcp6c_update_entry(STATE_IA_PD, &entry, 0)) updated_IAs++; syslog(LOG_INFO, "%s/%d preferred %d valid %d", @@ -1797,7 +1797,7 @@ static unsigned int dhcpv6_parse_ia(void *opt, void *end, int *ret) } if (update_state) { - if (odhcp6c_update_entry(STATE_IA_NA, &entry, 0, 0)) + if (odhcp6c_update_entry(STATE_IA_NA, &entry, 0)) updated_IAs++; syslog(LOG_INFO, "%s preferred %d valid %d", diff --git a/src/odhcp6c.c b/src/odhcp6c.c index 8b880e3..7b1a387 100644 --- a/src/odhcp6c.c +++ b/src/odhcp6c.c @@ -939,64 +939,20 @@ static struct odhcp6c_entry* odhcp6c_find_entry(enum odhcp6c_state state, const } bool odhcp6c_update_entry(enum odhcp6c_state state, struct odhcp6c_entry *new, - uint32_t safe, unsigned int holdoff_interval) + unsigned int holdoff_interval) { struct odhcp6c_entry *x = odhcp6c_find_entry(state, new); - uint32_t new_valid; - - /* - * "safe" refers to https://www.rfc-editor.org/rfc/rfc4862#section-5.5.3 - * section e; it is either the two hours in seconds or zero when (e) - * does not apply. - * - * The base condition for applying safe is that there is already a - * matching prefix (and safe itself must be set). - */ - if (safe && x) { - if (new->valid > safe || new->valid > x->valid) { - /* - * 1: If the received Valid Lifetime is greater than 2 hours or - * greater than RemainingLifetime, set the valid lifetime of the - * corresponding address to the advertised Valid Lifetime. - */ - new_valid = new->valid; - } else if (x->valid <= safe) { - /* - * 2: If RemainingLifetime is less than or equal - * to 2 hours, ignore the Prefix Information option with - * regards to the valid lifetime, unless the Router - * Advertisement from which this option was obtained has - * been authenticated (e.g., via Secure Neighbor - * Discovery [RFC3971]). If the Router Advertisement - * was authenticated, the valid lifetime of the - * corresponding address should be set to the Valid - * Lifetime in the received option. - * - * Since authenticated advertisements aren't supported we - * always keep the old value. - */ - new_valid = x->valid; - } else { - /* - * 3: Otherwise, reset the valid lifetime of the corresponding - * address to 2 hours. - */ - new_valid = safe; - } - } else { - new_valid = new->valid; - } if (x) { - if (holdoff_interval && new_valid >= x->valid && - new_valid != UINT32_MAX && - new_valid - x->valid < holdoff_interval && + if (holdoff_interval && new->valid >= x->valid && + new->valid != UINT32_MAX && + new->valid - x->valid < holdoff_interval && new->preferred >= x->preferred && new->preferred != UINT32_MAX && new->preferred - x->preferred < holdoff_interval) return false; - x->valid = new_valid; + x->valid = new->valid; x->preferred = new->preferred; x->t1 = new->t1; x->t2 = new->t2; diff --git a/src/odhcp6c.h b/src/odhcp6c.h index 42c645d..b229412 100644 --- a/src/odhcp6c.h +++ b/src/odhcp6c.h @@ -576,7 +576,7 @@ void* odhcp6c_get_state(enum odhcp6c_state state, size_t *len); // Entry manipulation bool odhcp6c_update_entry(enum odhcp6c_state state, struct odhcp6c_entry *new, - uint32_t safe, unsigned int holdoff_interval); + unsigned int holdoff_interval); void odhcp6c_expire(bool expire_ia_pd); uint32_t odhcp6c_elapsed(void); diff --git a/src/ra.c b/src/ra.c index dcc5fd6..ca9e691 100644 --- a/src/ra.c +++ b/src/ra.c @@ -437,7 +437,7 @@ bool ra_process(void) entry->valid = router_valid; entry->preferred = entry->valid; changed |= odhcp6c_update_entry(STATE_RA_ROUTE, entry, - 0, ra_holdoff_interval); + ra_holdoff_interval); // Parse hop limit changed |= ra_set_hoplimit(adv->nd_ra_curhoplimit); @@ -478,8 +478,18 @@ bool ra_process(void) if (entry->priority > 0) changed |= odhcp6c_update_entry(STATE_RA_ROUTE, entry, - 0, ra_holdoff_interval); + ra_holdoff_interval); } else if (opt->type == ND_OPT_PREFIX_INFORMATION && opt->len == 4) { + /* + * We implement draft-ietf-6man-slaac-renum-11 here: + * https://datatracker.ietf.org/doc/html/draft-ietf-6man-slaac-renum-11#section-5.4 + * + * This removes the two hour magic and instead just uses the new + * data. If the lifetime is zero, then the prefix is removed. + * + * An entry with lifetime zero is added. odhcp6c_expire will remove + * it again. odhcp6c_expire is called at the end of this function. + */ struct nd_opt_prefix_info *pinfo = (struct nd_opt_prefix_info*)opt; entry->router = any; entry->target = pinfo->nd_opt_pi_prefix; @@ -497,7 +507,7 @@ bool ra_process(void) if ((pinfo->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK) && !ptp_link) changed |= odhcp6c_update_entry(STATE_RA_ROUTE, entry, - 7200, ra_holdoff_interval); + ra_holdoff_interval); if (!(pinfo->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO) || pinfo->nd_opt_pi_prefix_len != 64) @@ -507,7 +517,7 @@ bool ra_process(void) entry->target.s6_addr32[3] = lladdr.s6_addr32[3]; changed |= odhcp6c_update_entry(STATE_RA_PREFIX, entry, - 7200, ra_holdoff_interval); + ra_holdoff_interval); } else if (opt->type == ND_OPT_RECURSIVE_DNS && opt->len > 2) { entry->router = from.sin6_addr; entry->priority = 0; @@ -520,7 +530,7 @@ bool ra_process(void) memcpy(&entry->target, &opt->data[6 + i * sizeof(entry->target)], sizeof(entry->target)); changed |= odhcp6c_update_entry(STATE_RA_DNS, entry, - 0, ra_holdoff_interval); + ra_holdoff_interval); } } else if (opt->type == ND_OPT_DNSSL && opt->len > 1) { uint32_t *valid = (uint32_t*)&opt->data[2]; @@ -542,7 +552,7 @@ bool ra_process(void) continue; changed |= odhcp6c_update_entry(STATE_RA_SEARCH, entry, - 0, ra_holdoff_interval); + ra_holdoff_interval); entry->auxlen = 0; } } -- 2.30.2